<?php

/**
 * Author: day
 * Date: 2018-09-12 11:04
 * Desc:
 * 订单拉取策略，通过组合的方式嵌入到注单拉取程序中
 */
namespace App\Console\Commands\ThirdOrder;

use App\Models\Order;
use App\Models\OrderRepairRecord;
use common\enum\CommonEnum;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\DB;
use common\utils\SysCode;

class OrderStrategy
{

    /**
     * 获取注单拉取的键值，目前有两种情况：
     * 1.时间
     * 2.id （SB，UG，HC等）
     * TODO: 支持后台设置区间拉取
     * @param $lockKey
     * @param $updateKey
     * @param string $fgKeys
     * @return mixed
     * @throws \Exception
     */
    public static function getUpdateKey($lockKey, $updateKey, $fgKeys = "")
    {
        $redis = Redis::connection();
        //是否补单中
        $repairStart = self::getRepairTime ($updateKey,1);
        if ($repairStart){
            return $repairStart;
        }
        // 检测是否需要重新拉取注单，每次重拉 1 小时前的注单
        $startKey = $redis->get($updateKey);
        if ($startKey === false || is_null ($startKey)) {
            $msg = "获取更新时间的 key 失败。如果是第一次使用请先设置该值！redis: key: {$updateKey} value: date('Y-m-d H:i:s')";
            Log::info($msg);
            return date("Y-m-d H:i:s", time () - 2 * 60);
        }
        if ($startKey){
            if (time()-strtotime ($startKey) > 60*60){
                return $startKey;
            }
        }
        $needFix = Redis::set($lockKey, date("Y-m-d H:i:s"), 'nx', 'ex', 10 * 60);
        if ($needFix) {
            $redis->set($updateKey, date("Y-m-d H:i:s", time() - 10 * 60));
            if ($fgKeys) {
                $fgKeys = $redis->keys($fgKeys . '*');
                foreach ($fgKeys as $fgKey){
                    $redis->del($fgKey);
                }
            }
        }
        return date("Y-m-d H:i:s", strtotime($startKey) - 2 * 60);
    }
    /**
     * 获取注单拉取的键值，目前有两种情况：
     * 1.时间
     * 2.id （SB，UG，HC等）本方法用于id
     * @param $locktime
     * @param $updateKey
     * @param string $lockid
     * @return mixed
     * @throws \Exception
     */
    public static function getUpdateKeyId($locktime, $updateKey, $lockid)
    {
        // 检测是否需要重新拉取注单，每次重拉 1 小时前的注单
        $redis = Redis::connection();
        //是否补单中
        $repairStart = self::getRepairTime ($updateKey,2);
        if ($repairStart){
            return $repairStart;
        }

        $startKey = $redis->get($updateKey);  //获取当前拉取id
        $needFix = $redis->set($locktime, date("Y-m-d H:i:s"), 'nx', 'ex', 60 * 10);
        if ($needFix) {
            $startKey = $redis->get($lockid);  //1个小时前的ID
            $redis->del($lockid); //删除1小时前的id
            $startKey_ex = $redis->get($updateKey);          //获取当前拉取id
            $redis->set($lockid, $startKey_ex, 'nx', 'ex', 60 * 11); //保存当前拉取id，1小时后重拉使用
        }
        //$startKey = $redis->get($updateKey);
        if ($startKey === false || is_null ($startKey)) {
            $msg = "获取更新时间的 key 失败。如果是第一次使用请先设置该值！redis: key: {$updateKey} value: 0";
            Log::info($msg);
            return 0;
        }
        return $startKey;
    }
    //获取补单时拉单起始时间或id
    public static function getRepairTime($updateKey,$type=1)
    {
        $partner_key = explode (':',$updateKey);
        $repairInfo = OrderRepairRecord::where(['partner_name'=>$partner_key[0],'status'=>CommonEnum::REPAIR_STATUS_PENDING])->first();
        if ($repairInfo){
            if ($type == 1) {
                return $repairInfo->current_time;
            }else{
                $repair_start = Order::where('bet_time','<=',$repairInfo->current_time)->select(['last_version_key'])->orderBy('bet_time','desc')->first();
                if (!$repair_start) {
                    return;
                }
                return  $repair_start->last_version_key;
            }
        }
    }
    //更新补单表中数据
    public static function UpdateRepairTime($partnerName,$latestUpdateKey,$latestUpdateKeyId)
    {
        $repairModel = OrderRepairRecord::where(['partner_name' => $partnerName, 'status' =>CommonEnum::REPAIR_STATUS_PENDING ])->first();
        if ($repairModel){
            $time = time ();
            if ($latestUpdateKey){
                if (is_numeric ($latestUpdateKey)){
                    if (strlen($latestUpdateKey)>10){
                        $time = $latestUpdateKey/CommonEnum::MILLISECOND;
                    }else{
                        $time = $latestUpdateKey;
                    }
                }else{
                    $time  = strtotime ($latestUpdateKey);
                }
            }
            if ($latestUpdateKeyId){
                $order_time = Order::where('last_version_key','<=',$latestUpdateKeyId)
                    ->where(['partner_name' => $partnerName])
                    ->select(['bet_time'])->orderBy('bet_time','desc')->first()->toArray();
                $time = strtotime($order_time['bet_time']);
            }
            $res = [];
            if($time < strtotime ($repairModel->end_time)){
                $end = date ('Y-m-d H:i:s',$time);
                $order_num = Order::select(DB::raw('count(id) as num'))
                    ->where(['partner_name' => $partnerName])
                    ->where('bet_time','>' ,$repairModel->current_time)
                    ->where('bet_time','<=' ,$end)
                    ->first()->toArray();
                $res['bet_count'] = $repairModel->bet_count + $order_num['num'];
                $res['current_time'] = date ('Y-m-d H:i:s',$time);
            }else {
                $order_num = Order::select(DB::raw('count(id) as num'))
                    ->where(['partner_name' => $partnerName])
                    ->whereBetween('bet_time',[$repairModel->begin_time,$repairModel->end_time])->first()->toArray();
                $res['bet_count'] = $order_num['num'];
                $res['status'] = CommonEnum::REPAIR_STATUS_FINISH;
                $res['current_time'] = date ('Y-m-d H:i:s',$time);
            }
            $repairModel->update($res);
        }else{
            return false;
        }
    }

}
